﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;

using ThreadSafeControls;

namespace ThreadSafeControlsTest {
    public partial class ThreadSafeControlsTestForm : Form {

        private static readonly Color[] Colors;
        private static readonly Font[] Fonts;

        static ThreadSafeControlsTestForm() {
            Colors = new Color[] { Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Indigo, Color.Violet };

            var installedFonts = new InstalledFontCollection();
            var families = installedFonts.Families;
            var availableFonts = new List<Font>();
            for (int i = 0; i < families.Length; ++i) {
                var family = families[i];

                try {
                    if (family.IsStyleAvailable(FontStyle.Regular)) {
                        var font = new Font(family, Control.DefaultFont.Size);
                        availableFonts.Add(font);
                    }

                } catch (Exception) {
                    continue;
                }
            }

            Fonts = availableFonts.ToArray();
        }

        public ThreadSafeControlsTestForm() {
            InitializeComponent();
        }

        private void StartThreadSafeTestButton_Click(object sender, EventArgs e) {
            if (!ThreadSafeTestMainWorker.IsBusy)
                ThreadSafeTestMainWorker.RunWorkerAsync();
        }

        private void StopThreadSafeTestButton_Click(object sender, EventArgs e) {
            if (ThreadSafeTestMainWorker.IsBusy)
                ThreadSafeTestMainWorker.CancelAsync();
        }

        private void ThreadSafeTestMainWorker_DoWork(object sender, DoWorkEventArgs e) {
            var worker = sender as BackgroundWorker;
            if (sender == null)
                return;

            var rand = new Random();

            // Page 1
            var frm = this.AsThreadSafeControl();
            var tbx = ThreadSafeTestTextBox.AsThreadSafe();
            var lbx = ThreadSafeTestListBox.AsThreadSafe();
            var lvw = ThreadSafeTestListView.AsThreadSafe();
            var lblFontChanging = ThreadSafeTestFontChangingLabel.AsThreadSafeControl();
            var lblBlinking = ThreadSafeTestBlinkingLabel.AsThreadSafeControl();
            var lblMoving = ThreadSafeTestMovingLabel.AsThreadSafeControl();
            var btnStart = StartThreadSafeTestButton.AsThreadSafe();
            var btnStop = StopThreadSafeTestButton.AsThreadSafe();
            var prg = ThreadSafeTestProgressBar.AsThreadSafe();
            var dtm = ThreadSafeTestDateTimePicker.AsThreadSafe();
            var cbx = ThreadSafeTestComboBox.AsThreadSafe();
            var chk = ThreadSafeTestCheckBox.AsThreadSafe();
            var rbn = ThreadSafeTestRadioButton.AsThreadSafe();

            // Page 2
            var tvw = ThreadSafeTestTreeView.AsThreadSafe();

            while (!worker.CancellationPending) {
                // randomly perform one of the following GUI updates on page 1
                switch (rand.Next(0, 24)) {
                    case 0:
                        // appends "text" to the textbox
                        tbx.AppendText("text");
                        break;
                    case 1:
                        // clear textbox
                        tbx.Clear();
                        break;
                    case 2:
                        // randomly change textbox's background color
                        tbx.BackColor = Colors[rand.Next(0, Colors.Length)];
                        break;
                    case 3:
                        // randomly add 1-10 item(s) to the listbox
                        var items = new object[rand.Next(1, 11)];
                        for (int i = 0; i < items.Length; ++i)
                            items[i] = "item" + i.ToString();

                        lbx.Items.AddRange(items);
                        break;
                    case 4:
                        // randomly remove a single item from the listbox
                        if (lbx.Items.Count > 0)
                            lbx.Items.RemoveAt(rand.Next(0, lbx.Items.Count));
                        break;
                    case 5:
                        // randomly clear the listbox
                        lbx.Items.Clear();
                        break;
                    case 6:
                        // randomly add 1-3 column(s) to the listview
                        int n = rand.Next(1, 4);
                        for (int i = 0; i < n; ++i)
                            lvw.Columns.Add("column" + i.ToString());
                        break;
                    case 7:
                        // randomly add 1-10 item(s) to the listview
                        var lvwItems = new ListViewItem[rand.Next(1, 11)];
                        for (int i = 0; i < lvwItems.Length; ++i)
                            lvwItems[i] = new ListViewItem("item" + i.ToString());

                        lvw.Items.AddRange(lvwItems);
                        break;
                    case 8:
                        // randomly remove a single item from the listview
                        if (lvw.Items.Count > 0)
                            lvw.Items.RemoveAt(rand.Next(0, lvw.Items.Count));
                        break;
                    case 9:
                        // randomly change the text of an item in the listview
                        if (lvw.Items.Count > 0)
                            lvw.Items[rand.Next(0, lvw.Items.Count)].Text = rand.Next(0, 2) == 0 ? "Hello!" : "Goodbye!";
                        break;
                    case 10:
                        // randomly change the text of a subitem in the listview
                        if (lvw.Items.Count > 0 && lvw.Columns.Count > 0) {
                            var lvwItem = lvw.Items[rand.Next(0, lvw.Items.Count)];
                            if (lvwItem.SubItems.Count < lvw.Columns.Count)
                                lvwItem.SubItems.Add("text");
                            else
                                lvwItem.SubItems[rand.Next(0, lvwItem.SubItems.Count)].Text = rand.Next(0, 2) == 0 ? "Hello!" : "Goodbye!";
                        }
                        break;
                    case 11:
                        // randomly clear the columns in the listview
                        lvw.Columns.Clear();
                        break;
                    case 12:
                        // randomly clear the items in the listview
                        lvw.Items.Clear();
                        break;
                    case 13:
                        // randomly change start button's bg color
                        btnStart.BackColor = Colors[rand.Next(0, Colors.Length)];
                        break;
                    case 14:
                        // randomly change stop button's bg color
                        btnStop.BackColor = Colors[rand.Next(0, Colors.Length)];
                        break;
                    case 15:
                        // randomly change font-changing label's font
                        lblFontChanging.Font = Fonts[rand.Next(0, Fonts.Length)];
                        break;
                    case 16:
                        // make blinking label appear/disappear
                        lblBlinking.Visible = !lblBlinking.Visible;
                        break;
                    case 17:
                        // randomly change moving label's position
                        lblMoving.Left = rand.Next(0, frm.Width - lblMoving.Width);
                        break;
                    case 18:
                        // randomly change the value of the progressbar
                        prg.Value = rand.Next(prg.Minimum, prg.Maximum + 1);
                        break;
                    case 19:
                        // randomly change the value of the datetimepicker
                        var range = dtm.MaxDate - dtm.MinDate;
                        var milliseconds = range.TotalMilliseconds;
                        dtm.Value = dtm.MinDate + TimeSpan.FromMilliseconds(milliseconds * rand.NextDouble());
                        break;
                    case 20:
                        // randomly add a value to the combobox or clear it
                        if (rand.Next(2) == 1)
                            cbx.Items.Clear();
                        else
                            cbx.Items.Add("Item" + (cbx.Items.Count + 1).ToString());
                        break;
                    case 21:
                        // randomly change the selected index of the combobox
                        if (cbx.Items.Count > 0)
                            cbx.SelectedIndex = rand.Next(0, cbx.Items.Count);
                        break;
                    case 22:
                        // randomly check/uncheck the checkbox
                        chk.Checked = !chk.Checked;
                        break;
                    case 23:
                        // randomly check/uncheck the radiobutton
                        rbn.Checked = !rbn.Checked;
                        break;
                }

                // randomly perform one of the following GUI updates on page 1
                switch (rand.Next(0, 5)) {
                    case 0:
                        // clear the entire treeview
                        tvw.Nodes.Clear();
                        break;
                    case 1:
                        // add a random node to the root
                        tvw.Nodes.Add("node" + tvw.Nodes.Count.ToString());
                        break;
                    case 2:
                        // add a node at the lowest level
                        if (tvw.Nodes.Count < 1) {
                            tvw.Nodes.Add("node0");
                            break;
                        }

                        var randomLeafNode = tvw.Nodes[rand.Next(0, tvw.Nodes.Count)];
                        while (randomLeafNode.Nodes.Count > 0)
                            randomLeafNode = randomLeafNode.Nodes[0];

                        randomLeafNode.Nodes.Add("node" + randomLeafNode.Nodes.Count.ToString());
                        break;
                    case 3:
                        // sort the treeview
                        tvw.Sort();
                        break;
                    case 4:
                        // pick a random node and change its text
                        if (tvw.Nodes.Count < 1)
                            break;

                        var randomRootNode = tvw.Nodes[rand.Next(0, tvw.Nodes.Count)];
                        randomRootNode.Text = "blahblahblah";
                        break;
                }
            }
        }

        private void ThreadSafeTestCheckedListBoxStartButton_Click(object sender, EventArgs e) {
            if (!ThreadSafeTestCheckedListBoxWorker.IsBusy)
                ThreadSafeTestCheckedListBoxWorker.RunWorkerAsync();
        }

        private void ThreadSafeTestCheckedListBoxStopButton_Click(object sender, EventArgs e) {
            if (ThreadSafeTestCheckedListBoxWorker.IsBusy)
                ThreadSafeTestCheckedListBoxWorker.CancelAsync();
        }

        private void ThreadSafeTestCheckedListBoxClearButton_Click(object sender, EventArgs e) {
            var clbx = ThreadSafeTestCheckedListBox.AsThreadSafe();

            clbx.Items.Clear();
        }

        private void ThreadSafeTestCheckedListBoxMultiColumn_CheckedChanged(object sender, EventArgs e) {
            ThreadSafeTestCheckedListBox.MultiColumn = ThreadSafeTestCheckedListBoxMultiColumn.Checked;
        }

        private void ThreadSafeTestCheckedListBoxWorker_DoWork(object sender, DoWorkEventArgs e) {
            var worker = sender as BackgroundWorker;
            if (worker == null)
                return;

            var clbx = ThreadSafeTestCheckedListBox.AsThreadSafe();
            var nudNumItems = ThreadSafeTestCheckedListBoxNumItems.AsThreadSafe();
            var nudMilliseconds = ThreadSafeTestCheckedListBoxMilliseconds.AsThreadSafe();
            var cbx = ThreadSafeTestCheckedListBoxChecked.AsThreadSafe();

            while (!worker.CancellationPending) {
                for (int i = 0; i < decimal.ToInt32(nudNumItems.Value); ++i) {
                    clbx.Items.Add("item" + (clbx.Items.Count + 1).ToString(), cbx.Checked);

                    // sleep so that user sees process of items being added
                    System.Threading.Thread.Sleep(50);
                }

                System.Threading.Thread.Sleep(decimal.ToInt32(nudMilliseconds.Value));
            }
        }

    }
}
